#ifndef DSPSIMULATOR_DSPSIMULATOR_H
#define DSPSIMULATOR_DSPSIMULATOR_H

#include <vector>
#include <queue>
#include "simulator/instFetcher.h"
#include "dspSimulator/dspSimulator/dspInstFetcher.h"
#include "simulator/simulator.h"
#include "dspSimulator/targetMachine/dspMachine.h"
#include <simulator/instruction/instruction.h>
#include <simulator/instruction/delayInstruction.h>
#include <dspSimulator/targetMachine/interruptHandle.h>
#include "simulator/command/command.h"
#include <dspSimulator/command/next.h>
#include <dspSimulator/command/printARegs.h>
#include <dspSimulator/command/printBRegs.h>
#include <dspSimulator/command/continue.h>
#include <dspSimulator/command/printAReg.h>
#include <dspSimulator/command/printBReg.h>
#include <dspSimulator/command/printCReg.h>
#include <dspSimulator/command/breakPoint.h>
#include <dspSimulator/command/exit.h>
#include <dspSimulator/command/watchMemory.h>
#include <dspSimulator/command/snapshot.h>
#include <dspSimulator/command/saveAndrestore.h>
#include <dspSimulator/operand/registerKind.h>
#include "dspSimulator/irGenerator/irGenerator.h"
#include "dspSimulator/targetMachine/dspInstruction.h"
#include "dspSimulator/operand/operand.h"
#include "dspSimulator/operand/immediate32.h"
#include "dspSimulator/operand/singleReg.h"
#include "dspSimulator/operand/doubleReg.h"
#include "dspSimulator/operand/fourReg.h"

class DSPSimulator : public Simulator {
    friend class NextCommand;

    friend class PrintARegsCommand;

    friend class PrintBRegsCommand;

    friend class ContinueCommand;

    friend class PrintARegCommand;

    friend class PrintBRegCommand;

    friend class PrintCRegCommand;

    friend class BreakPointCommand;

    friend class WatchMemoryCommand;

    friend class SaveAndRestoreCommand;

    using RegCopy = std::unordered_map<std::string, llvm::Value *>;

private:
    std::shared_ptr<IRGenerator> m_irGenerator;

    std::string m_currentFuncName;    // 当前正在生成的ir函数名
    llvm::Function *m_currentFunc;    // 当前正在生成的ir函数
    u64 m_numOfInstruction;         // 记录当前已经完成执行的指令数
    u64 m_numOfInsertNOP;           // 记录插入在执行包之后的nop指令数

public:
    using ExecutePacket = std::vector<std::shared_ptr<Instruction>>;

    DSPSimulator(std::shared_ptr<TargetMachine> &targetMachine, std::shared_ptr<InstFetcher> &instFetcher,
                 std::shared_ptr<LLVMJit> &llvmJit);

    ~DSPSimulator() override = default;

    void run() override;

    /**
     * 添加目标机器支持的指令原型
     */
    void addAllInstructionProto() override;

protected:

    /**
    * 取指函数
    * @return 当前周期取指器取出的指令数据集合
    */
    std::vector<std::shared_ptr<InstInfo>> fetch() override;

    /**
    * 根据指令数据集合解码出一系列对应的指令对象
    * @param instInfo 指令数据集合
    * @return 解码出的一系列指令
    */
    ExecutePacket decode(std::vector<std::shared_ptr<InstInfo>> &instInfos) override;

    /**
    * 执行指令
    * @param instruction 一系列指令
    */
    void execute(ExecutePacket &executePacket) override;

    /**
     * 创建寄存器拷贝
     * @param instructions 指令执行包
     * @return 指令执行包中每条指令需要用到的寄存器的数据拷贝
     */
    RegCopy createRegCopy(ExecutePacket &executePacket);

    /**
     * 创建指令条件的寄存器拷贝
     * @param executePacket 指令执行包
     * @param regCopy 指令条件的寄存器拷贝
     */
    void createConditionRegCopy(ExecutePacket &executePacket, RegCopy &regCopy);

    /**
     * 打印指令执行包
     */
    void printExecutePacket(ExecutePacket &executePacket) const;

    static void nextCycle(Timer *timer);

    void createFunctionHead();

    void createFunctionTail();
};

#endif //DSPSIMULATOR_DSPSIMULATOR_H
